package com.riversoft.weixin.pay.micro;

import com.riversoft.weixin.common.WxSslClient;
import com.riversoft.weixin.common.exception.WxRuntimeException;
import com.riversoft.weixin.common.util.JsonMapper;
import com.riversoft.weixin.common.util.RandomStringGenerator;
import com.riversoft.weixin.common.util.XmlObjectMapper;
import com.riversoft.weixin.pay.PayWxClientFactory;
import com.riversoft.weixin.pay.base.PaySetting;
import com.riversoft.weixin.pay.base.WxEndpoint;
import com.riversoft.weixin.pay.micro.bean.*;
import com.riversoft.weixin.pay.micro.wrapper.*;
import com.riversoft.weixin.pay.util.SignatureUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.SortedMap;

/**
 * 小微商户相关接口
 */
public class MicroMerchants {

    private static Logger logger = LoggerFactory.getLogger(MicroMerchants.class);

    private PaySetting paySetting;

    public void setPaySetting(PaySetting paySetting) {
        this.paySetting = paySetting;
    }

    private WxSslClient wxSslClient;

    public static MicroMerchants defaultPayments() {
        return with(PaySetting.defaultSetting());
    }

    public static MicroMerchants with(PaySetting paySetting) {
        MicroMerchants microMerchants = new MicroMerchants();
        microMerchants.setPaySetting(paySetting);
        microMerchants.setWxSslClient(PayWxClientFactory.getInstance().with(paySetting));
        return microMerchants;
    }

    public void setWxSslClient(WxSslClient wxSslClient) {
        this.wxSslClient = wxSslClient;
    }

    private void setBaseSettings(BaseMicroSettings wrapper) {
        wrapper.setMchId(paySetting.getMchId());
    }

    private void sign(BaseMicroSettings wrapper, SortedMap<String, Object> generals) {
        String nonce = RandomStringGenerator.getRandomStringByLength(32);
        generals.put("nonce_str", nonce);
        generals.put("mch_id", paySetting.getMchId());

        wrapper.setNonce(nonce);
        wrapper.setSign(SignatureUtil.HmacSha256Sign(generals, paySetting.getKey()));
    }

    /**
     * 获取 平台证书序列号
     * @param certficatesRequest
     * @return
     */
    public MicroMerchantCertficatesResponse getCertficates(MicroMerchantCertficatesRequest certficatesRequest) {

        MicroMerchantCertficatesRequestWrapper wrapper=new MicroMerchantCertficatesRequestWrapper();
        wrapper.setRequest(certficatesRequest);
        setBaseSettings(wrapper);
        SortedMap<String, Object> facePayOrderRequestMap = JsonMapper.nonEmptyMapper().getMapper().convertValue(wrapper, SortedMap.class);
        sign(wrapper, facePayOrderRequestMap);

        String url = WxEndpoint.get("url.applyment.micro.getcertficates");
        try {
            String xml = XmlObjectMapper.nonEmptyMapper().toXml(wrapper);
            logger.info("小微商户 getCertficates request: {}", xml);
            String response = wxSslClient.post(url, xml);
            logger.info("小微商户 getCertficates response: {}", response);

            MicroMerchantCertficatesResponseWrapper responseWrapper = XmlObjectMapper.defaultMapper().fromXml(response, MicroMerchantCertficatesResponseWrapper.class);
            return responseWrapper.getResponse();
        } catch (Exception e) {
            throw new WxRuntimeException(999, "pre order failed:" + e.getMessage());
        }
    }

    /**
     *  图片上传接口
     * @param uploadMediaRequest
     * @return
     */
    public MicroMerchantUploadMediaResponse uploadMedia(MicroMerchantUploadMediaRequest uploadMediaRequest) {

        MicroMerchantUploadMediaRequestWrapper wrapper=new MicroMerchantUploadMediaRequestWrapper();
        wrapper.setRequest(uploadMediaRequest);
        setBaseSettings(wrapper);
        SortedMap<String, Object> facePayOrderRequestMap = JsonMapper.nonEmptyMapper().getMapper().convertValue(wrapper, SortedMap.class);
        sign(wrapper, facePayOrderRequestMap);

        String url = WxEndpoint.get("url.applyment.micro.uploadmedia");
        try {
            String xml = XmlObjectMapper.nonEmptyMapper().toXml(wrapper);
            logger.info("小微商户 uploadMedia request: {}", xml);
            String response = wxSslClient.post(url, xml);
            logger.info("小微商户 uploadMedia response: {}", response);

            MicroMerchantUploadMediaResponseWrapper responseWrapper = XmlObjectMapper.defaultMapper().fromXml(response, MicroMerchantUploadMediaResponseWrapper.class);
            return responseWrapper.getResponse();
        } catch (Exception e) {
            throw new WxRuntimeException(999, "pre order failed:" + e.getMessage());
        }
    }

    /**
     * 申请入驻接口
     * 使用申请入驻接口提交你的小微商户资料，申请后一般5分钟左右可以查询到具体的申请结果。
     * @param applyMentRequest
     * @return
     */
    public MicroMerchantApplyMentResponse applyMent(MicroMerchantApplyMentRequest applyMentRequest) {

        MicroMerchantApplyMentRequestWrapper wrapper=new MicroMerchantApplyMentRequestWrapper();
        wrapper.setRequest(applyMentRequest);
        setBaseSettings(wrapper);
        SortedMap<String, Object> facePayOrderRequestMap = JsonMapper.nonEmptyMapper().getMapper().convertValue(wrapper, SortedMap.class);
        sign(wrapper, facePayOrderRequestMap);

        String url = WxEndpoint.get("url.applyment.micro.submit");
        try {
            String xml = XmlObjectMapper.nonEmptyMapper().toXml(wrapper);
            logger.info("小微商户 applyMent request: {}", xml);
            String response = wxSslClient.post(url, xml);
            logger.info("小微商户 applyMent response: {}", response);

            MicroMerchantApplyMentResponseWrapper responseWrapper = XmlObjectMapper.defaultMapper().fromXml(response, MicroMerchantApplyMentResponseWrapper.class);
            return responseWrapper.getResponse();
        } catch (Exception e) {
            throw new WxRuntimeException(999, "pre order failed:" + e.getMessage());
        }
    }

    /**
     * 申请入驻状态查询
     * 使用申请入驻接口提交小微商户资料后，一般5分钟左右可以通过该查询接口查询具体的申请结果。
     * @param applyMentStateRequest
     * @return
     */
    public MicroMerchantApplyMentStateResponse getApplyMentState(MicroMerchantApplyMentStateRequest applyMentStateRequest) {
        MicroMerchantApplyMentStateRequestWrapper wrapper=new MicroMerchantApplyMentStateRequestWrapper();
        wrapper.setRequest(applyMentStateRequest);
        setBaseSettings(wrapper);
        SortedMap<String, Object> facePayOrderRequestMap = JsonMapper.nonEmptyMapper().getMapper().convertValue(wrapper, SortedMap.class);
        sign(wrapper, facePayOrderRequestMap);

        String url = WxEndpoint.get("url.applyment.micro.getstate");
        try {
            String xml = XmlObjectMapper.nonEmptyMapper().toXml(wrapper);
            logger.info("小微商户 getstate request: {}", xml);
            String response = wxSslClient.post(url, xml);
            logger.info("小微商户 getstate response: {}", response);

            MicroMerchantApplyMentStateResponseWrapper responseWrapper = XmlObjectMapper.defaultMapper().fromXml(response, MicroMerchantApplyMentStateResponseWrapper.class);
            return responseWrapper.getResponse();
        } catch (Exception e) {
            throw new WxRuntimeException(999, "pre order failed:" + e.getMessage());
        }
    }

}
